package userrank

import (
	"context"
	"encoding/json"
	"strconv"
	"strings"

	"mall/common/cachex"
	"mall/common/globalkey"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/logic/setting/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/setting/rpc/settingclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type (
	// UserRank is an interface to be customized, add more methods here,
	// and implement the added methods in customUserRank.
	UserRank interface {
		List(userId uint64) ([]*types.UserRankInfo, error)
	}

	customUserRank struct {
		ctx    context.Context
		svcCtx *svc.ServiceContext
	}
)

func NewUserRank(ctx context.Context, svcCtx *svc.ServiceContext) UserRank {
	return &customUserRank{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *customUserRank) List(userId uint64) (resp []*types.UserRankInfo, err error) {
	memberRankKey := cachex.LocalMemberRank

	if localCacheMemberRankList, ok := l.svcCtx.LocalCache.Get(memberRankKey); ok {
		resp = localCacheMemberRankList.([]*types.UserRankInfo)
	} else {
		resp, err = l.list(userId)
		if err != nil {
			return nil, err
		}

		l.svcCtx.LocalCache.Set(memberRankKey, resp)
	}

	return resp, nil
}

// Todo: review
func (l *customUserRank) list(userId uint64) (resp []*types.UserRankInfo, err error) {
	preload := "memberRank:Id,Name,Code,Desc,PicId,PicUrl"
	preload += ";memberRankRestriction:Id,RankId,TaskId,Threshold" +
		";memberRankRule:Id,RankId,RuleType,Regions,Mode,Value,PeriodType,Quota"
	eagerLoad := "memberRank:memberRankRestriction,memberRankRule"
	filters := []string{"Status,equalTo:" + strconv.FormatInt(int64(globalkey.StatusEnabled), 10)}
	res, err := l.svcCtx.SettingRpc.GetMemberRankList(l.ctx, &settingclient.BaseListReq{
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		Sorter:     pointy.GetPointer("Sort:0"),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(globalkey.ThirdPartyPlatformWechatMini),
	})
	if err != nil {
		return nil, err
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			var restrictions []*types.UserRankRestrictionInfo
			if len(v.Restrictions) > 0 {
				for _, rv := range v.Restrictions {
					restrictions = append(restrictions, &types.UserRankRestrictionInfo{
						Id:        rv.Id,
						RankId:    rv.RankId,
						TaskId:    rv.TaskId,
						Threshold: rv.Threshold,
					})
				}
			}
			var rules []*types.UserRankRuleInfo
			if len(v.Rules) > 0 {
				for _, rv := range v.Rules {
					var regions []*types.TreeNode
					if rv.Regions != nil {
						if err := json.Unmarshal([]byte(*rv.Regions), &regions); err != nil {
							logx.Errorw("UserRank List Rules.Regions json.Unmarshal err", logx.Field("detail", err.Error()))
						}
					}
					var ruleTypeText string = util.GetUserRankRuleTypeText(rv.RuleType)
					var periodTypeText string = util.GetUserRankPeriodTypeText(rv.PeriodType)
					rules = append(rules, &types.UserRankRuleInfo{
						Id:             rv.Id,
						RankId:         rv.RankId,
						RuleType:       rv.RuleType,
						RuleTypeText:   ruleTypeText,
						Regions:        regions,
						Mode:           rv.Mode,
						Value:          rv.Value,
						PeriodType:     rv.PeriodType,
						PeriodTypeText: periodTypeText,
						Quota:          rv.Quota,
					})
				}
			}

			resp = append(resp, &types.UserRankInfo{
				Id:           v.Id,
				Name:         v.Name,
				Slug:         v.Code,
				Desc:         v.Description,
				MediaId:      v.PicId,
				MediaUrl:     v.PicUrl,
				Restrictions: restrictions,
				Rules:        rules,
			})
		}
	}

	return resp, nil
}
